#include "Draw/lcd.h"
#include "Init/lcd_drive.h"
// #include "Font/lcdfont.h"
#include "Font\lcdfont_Unispace.h"

/******************************************************************************
      函数说明：在指定区域填充图案，需在制定范围内
      入口数据： pFont  原始字模
                pRaw   输出缓存
                color  填充颜色
      返回值：  无
******************************************************************************/

void LCD_Font2Raw(unsigned char *pFont, unsigned short *pRaw, unsigned short pixNum, unsigned short color, unsigned short Bcolor)
{
    unsigned short point = 0;
    color                = (color >> 8) + (color << 8);
    Bcolor               = (Bcolor >> 8) + (Bcolor << 8);
    for (unsigned short i = 0; i < pixNum; i++) {
        pRaw[point++] = (pFont[i / 8] & 0x01 << (i % 8)) ? color : Bcolor;
    }
}

/******************************************************************************
      函数说明：在指定区域填充图案，需在制定范围内
      入口数据：xsta,ysta   起始坐标
                xend,yend   终止坐标
                pBuff       要填充的图案
      返回值：  无
******************************************************************************/
void LCD_RAW(unsigned short xsta, unsigned short ysta, unsigned short xend, unsigned short yend, unsigned short *pBuff)
{
    LCD_CS_Clr();
    LCD_Address_Set(xsta, ysta, xend, yend); // 设置显示范围
    HAL_SPI_Transmit(&hspi1, (uint8_t *)pBuff, 2 * (xend - xsta + 1) * (yend - ysta + 1), 0x0F);
    LCD_CS_Set();
}


const uint8_t yOffsets[8] = {0, 4, 8, 12, 16, 20, 24, 28};
#define SIZE_X_8  7
#define SIZE_X_16 15
void LCD_ShowChar(unsigned short x, unsigned short y, unsigned char num, unsigned short fc, unsigned short bc, unsigned char sizey)
{
    unsigned short RawBuff[64];
    num = num - ' '; // 得到偏移后的值

    switch (sizey) {
        case 12: // 12*6 12*8
            LCD_Font2Raw((uint8_t *)&ascii_1206[num], RawBuff, 64, fc, bc);
            LCD_RAW(x, y, x + SIZE_X_8, y + 8 - 1, RawBuff);
            LCD_Font2Raw((uint8_t *)&ascii_1206[num][8], RawBuff, 32, fc, bc);
            LCD_RAW(x, y + 8, x + SIZE_X_8, y + 12 - 1, RawBuff);
            break;
        case 16: // 16*8 16*8
            LCD_Font2Raw((uint8_t *)&ascii_1608[num], RawBuff, 64, fc, bc);
            LCD_RAW(x, y, x + SIZE_X_8, y + 7, RawBuff);
            LCD_Font2Raw((uint8_t *)&ascii_1608[num][8], RawBuff, 64, fc, bc);
            LCD_RAW(x, y + 8, x + SIZE_X_8, y + sizey - 1, RawBuff);
            break;
        case 24: // 24*12 24*16 12*8*4
            for (int i = 0; i < 6; i++) {
                LCD_Font2Raw((uint8_t *)&ascii_2412[num][i * 8], RawBuff, 64, fc, bc);
                LCD_RAW(x, y + yOffsets[i], x + SIZE_X_16, y + yOffsets[i] + 3, RawBuff);
            }
            break;
        case 32: // 32*16 32*16
            for (int i = 0; i < 8; i++) {
                LCD_Font2Raw((uint8_t *)&ascii_3216[num][i * 8], RawBuff, 64, fc, bc);
                LCD_RAW(x, y + yOffsets[i], x + SIZE_X_16, y + yOffsets[i] + 3, RawBuff);
            }
            break;
        default:
            break;
    }
}

/******************************************************************************
      函数说明：在指定区域填充颜色
      入口数据：xsta,ysta   起始坐标
                xend,yend   终止坐标
                                color       要填充的颜色
      返回值：  无
******************************************************************************/
void LCD_Fill(unsigned short xsta, unsigned short ysta, unsigned short xend, unsigned short yend, unsigned short color)
{
    unsigned short i, j;
    LCD_CS_Clr();
    unsigned short len = (xend - xsta) / 2;
    unsigned short pbuff[len];

    color = (((color & 0xff00) >> 8) | ((color & 0x00ff) << 8));
    for (j = 0; j < len; j++) {
        pbuff[j] = color;
    }
    LCD_Address_Set(xsta, ysta, xend - 1, yend - 1); // 设置显示范围
    for (i = ysta; i < yend; i++) {
        HAL_SPI_Transmit(&LCD_SPI, (uint8_t *)pbuff, 2 * len, 0xff);
        HAL_SPI_Transmit(&LCD_SPI, (uint8_t *)pbuff, 2 * len, 0xff);
    }

    LCD_CS_Set();
}

/******************************************************************************
      函数说明：在指定位置画点
      入口数据：x,y 画点坐标
                color 点的颜色
      返回值：  无
******************************************************************************/
void LCD_DrawPoint(unsigned short x, unsigned short y, unsigned short color)
{
    LCD_Address_Set(x, y, x, y); // 设置光标位置
    LCD_WR_DATA(color);
}

/******************************************************************************
      函数说明：画线
      入口数据：x1,y1   起始坐标
                x2,y2   终止坐标
                color   线的颜色
      返回值：  无
******************************************************************************/
void LCD_DrawLine(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2, unsigned short color)
{
    unsigned short t;
    int xerr = 0, yerr = 0, delta_x, delta_y, distance;
    int incx, incy, uRow, uCol;
    delta_x = x2 - x1; // 计算坐标增量
    delta_y = y2 - y1;
    uRow    = x1; // 画线起点坐标
    uCol    = y1;
    if (delta_x > 0)
        incx = 1; // 设置单步方向
    else if (delta_x == 0)
        incx = 0; // 垂直线
    else {
        incx    = -1;
        delta_x = -delta_x;
    }
    if (delta_y > 0)
        incy = 1;
    else if (delta_y == 0)
        incy = 0; // 水平线
    else {
        incy    = -1;
        delta_y = -delta_y;
    }
    if (delta_x > delta_y)
        distance = delta_x; // 选取基本增量坐标轴
    else
        distance = delta_y;
    LCD_CS_Clr();
    for (t = 0; t < distance + 1; t++) {
        LCD_DrawPoint(uRow, uCol, color); // 画点
        xerr += delta_x;
        yerr += delta_y;
        if (xerr > distance) {
            xerr -= distance;
            uRow += incx;
        }
        if (yerr > distance) {
            yerr -= distance;
            uCol += incy;
        }
    }
    LCD_CS_Set();
}

/******************************************************************************
      函数说明：画矩形
      入口数据：x1,y1   起始坐标
                x2,y2   终止坐标
                color   矩形的颜色
      返回值：  无
******************************************************************************/
void LCD_DrawRectangle(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2, unsigned short color)
{
    LCD_DrawLine(x1, y1, x2, y1, color);
    LCD_DrawLine(x1, y1, x1, y2, color);
    LCD_DrawLine(x1, y2, x2, y2, color);
    LCD_DrawLine(x2, y1, x2, y2, color);
}

/******************************************************************************
      函数说明：画圆
      入口数据：x0,y0   圆心坐标
                r       半径
                color   圆的颜色
      返回值：  无
******************************************************************************/
void Draw_Circle(unsigned short x0, unsigned short y0, unsigned char r, unsigned short color)
{
    int a, b;
    a = 0;
    b = r;
    LCD_CS_Clr();
    while (a <= b) {
        LCD_DrawPoint(x0 - b, y0 - a, color); // 3
        LCD_DrawPoint(x0 + b, y0 - a, color); // 0
        LCD_DrawPoint(x0 - a, y0 + b, color); // 1
        LCD_DrawPoint(x0 - a, y0 - b, color); // 2
        LCD_DrawPoint(x0 + b, y0 + a, color); // 4
        LCD_DrawPoint(x0 + a, y0 - b, color); // 5
        LCD_DrawPoint(x0 + a, y0 + b, color); // 6
        LCD_DrawPoint(x0 - b, y0 + a, color); // 7
        a++;
        if ((a * a + b * b) > (r * r)) // 判断要画的点是否过远
        {
            b--;
        }
    }
    LCD_CS_Set();
}

/******************************************************************************
      函数说明：显示字符串
      入口数据：x,y显示坐标
                *p 要显示的字符串
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值：  无
******************************************************************************/
void LCD_ShowString(unsigned short x, unsigned short y, char *p, unsigned short fc, unsigned short bc, unsigned char sizey)
{
    while (*p != '\0') {
        LCD_ShowChar(x, y, *p, fc, bc, sizey);
        x += sizey / 2;
        p++;
    }
}

/******************************************************************************
      函数说明：显示数字
      入口数据：m底数，n指数
      返回值：  无
******************************************************************************/
unsigned int mypow(unsigned char m, unsigned char n)
{
    unsigned int result = 1;
    while (n--) result *= m;
    return result;
}

/******************************************************************************
      函数说明：显示整数变量
      入口数据：x,y显示坐标
                num 要显示整数变量
                len 要显示的位数
                fc 字的颜色
                bc 字的背景色
                sizey 字号
      返回值：  无
******************************************************************************/
void LCD_ShowIntNum(unsigned short x, unsigned short y, unsigned short num, unsigned char len, unsigned short fc, unsigned short bc, unsigned char sizey, unsigned char padding)
{
    unsigned char t, temp;
    unsigned char enshow = 0;
    unsigned char sizex  = sizey / 2;
    for (t = 0; t < len; t++) {
        temp = (num / mypow(10, len - t - 1)) % 10;
        if (enshow == 0 && t < (len - 1)) {
            if ((temp == 0) && (!padding)) {
                LCD_ShowChar(x + t * sizex, y, ' ', fc, bc, sizey);
                continue;
            } else
                enshow = 1;
        }
        LCD_ShowChar(x + t * sizex, y, temp + 48, fc, bc, sizey);
    }
}

/******************************************************************************
      函数说明：显示两位小数变量
      入口数据：x,y显示坐标
                num 要显示小数变量
                len 要显示的位数
                fc 字的颜色
                bc 字的背景色
                sizey 字号
      返回值：  无
******************************************************************************/
void LCD_ShowFloatNum1(unsigned short x, unsigned short y, float num, unsigned char len, unsigned short fc, unsigned short bc, unsigned char sizey)
{
    unsigned char sizex;
    sizex = sizey / 2;

    LCD_ShowIntNum(x, y, (int)num, len, fc, bc, sizey, 0);
    LCD_ShowChar(x + len * sizex, y, '.', fc, bc, sizey);
    LCD_ShowIntNum(x + (len + 1) * sizex, y, num * 100, 2, fc, bc, sizey, 1);
}

/******************************************************************************
      函数说明：显示图片
      入口数据：x,y起点坐标
                length 图片长度
                width  图片宽度
                pic[]  图片数组
      返回值：  无
******************************************************************************/
void LCD_ShowPicture(unsigned short x, unsigned short y, unsigned short length, unsigned short width, const unsigned char pic[])
{
    unsigned short i, j;
    unsigned int k = 0;
    LCD_Address_Set(x, y, x + length - 1, y + width - 1);
    for (i = 0; i < length; i++) {
        for (j = 0; j < width; j++) {
            LCD_WR_DATA8(pic[k * 2]);
            LCD_WR_DATA8(pic[k * 2 + 1]);
            k++;
        }
    }
}
